﻿#pragma once

namespace fast_io::details
{

template <::std::integral T>
inline constexpr T read_write_bytes_compute(::std::byte const *first, ::std::byte const *last) noexcept
{
	::std::ptrdiff_t sz{last - first};
	constexpr auto ul32mx{::std::numeric_limits<T>::max()};
	if constexpr (ul32mx < ::std::numeric_limits<::std::ptrdiff_t>::max())
	{
		if (ul32mx < sz)
		{
			sz = ul32mx;
		}
	}
	return static_cast<T>(sz);
}

inline ::std::int_least64_t nt_fpos_offset_addition(::std::uint_least64_t ucurrent, ::fast_io::intfpos_t off) noexcept
{
	if constexpr (sizeof(::std::int_least64_t) < sizeof(::fast_io::intfpos_t))
	{
		if (off < INT_LEAST64_MIN)
		{
			return 0;
		}
		else if (INT_LEAST64_MAX < off)
		{
			return -1;
		}
	}
	if (ucurrent > INT_LEAST64_MAX)
	{
		return -1;
	}
	::std::int_least64_t current{static_cast<::std::int_least64_t>(ucurrent)};
	::std::int_least64_t l64off{static_cast<::std::int_least64_t>(off)};
	if (l64off < 0)
	{
		::std::uint_least64_t l64abs{static_cast<::std::uint_least64_t>(static_cast<::std::uint_least64_t>(0) -
																		static_cast<::std::uint_least64_t>(l64off))};
		if (ucurrent < l64abs)
		{
			return 0;
		}
	}
	else
	{
		::std::uint_least64_t l64abs{static_cast<::std::uint_least64_t>(l64off)};
		constexpr ::std::uint_least64_t l64mx{
			static_cast<::std::uint_least64_t>(::std::numeric_limits<::std::int_least64_t>::max())};
		::std::uint_least64_t diff{static_cast<::std::uint_least64_t>(l64mx - l64abs)};
		if (diff < ucurrent)
		{
			return -1;
		}
		return current + l64off;
	}
	return current + l64off;
}

} // namespace fast_io::details
